package ucd.csi.comp30220.fall2011.oteop.collision;

import java.io.IOException;
import java.io.Serializable;
import java.util.Hashtable;
import javax.jmdns.JmDNS;
import javax.jmdns.ServiceInfo;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Session;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.exolab.jms.service.ServiceException;

import ucd.csi.comp30220.fall2011.oteop.OTEOP;
import ucd.csi.comp30220.fall2011.oteop.flight.FlightStatus;
import ucd.csi.comp30220.fall2011.oteop.navigation.Position;
import ucd.csi.comp30220.fall2011.oteop.util.PortFinder;

/**
 * Collision Server. 
 * Uses JMS Point-Point (Queues) to communicate with clients.
 *
 * @author David Haddock
 *
 */
public class CollisionServer implements MessageListener {

	// TODO dhaddock make communication with plane multi-threaded as per david's suggestion
	// TODO dhaddock what happens if there are multiple collisionservers running 
	
	private JmDNS jmDNS;
	private ServiceInfo serviceInfo;
	private int port;
	private CollisionDetectionManager manager;
	private Session session;

	/**
	 * Constructor for a collision server. 
	 * It creates and registers its collision service with jmdns
	 * @throws Exception 
	 */
	public CollisionServer() throws Exception {
	       
        final int port = PortFinder.getNextAvailable();
        new JmsSession(port, port+1);
        
		jmDNS = JmDNS.create();
		serviceInfo = ServiceInfo.create(OTEOP.JMDNS_TYPE_TCP_LOCAL,
		"collision", 
		Collision.JMDNS_SUB_TYPE, 
		port,
		"Collision Detection Service");

		jmDNS.registerService(serviceInfo);
		String providerUrl = "tcp://localhost:" +port;
	      
        Hashtable<String, String> properties = new Hashtable<String, String>();
        properties.put(Context.INITIAL_CONTEXT_FACTORY, OTEOP.JAVA_NAMING_FACTORY_INITIAL);
        properties.put(Context.PROVIDER_URL, providerUrl);
        Context context = new InitialContext(properties);
        ConnectionFactory factory = (ConnectionFactory) context.lookup("ConnectionFactory");
        Connection connection = factory.createConnection();
        
        session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        final Destination destination = (Destination) context.lookup("queue1");
        MessageConsumer consumer = session.createConsumer(destination);
        consumer.setMessageListener(this);
        connection.start();
        
		manager = new CollisionDetectionManager();
		System.err.println("JmDNS service registered on " +providerUrl);
	}

	public Collision getLatestCollisionInformation(FlightStatus status) {
		return manager.getCollisionInfo(status);
	}
	
	public void stopBroadcastingServices() {
		jmDNS.unregisterAllServices();
	}

	public void onMessage(Message message) {
		ObjectMessage received = (ObjectMessage) message;
		try {
			FlightStatus status = (FlightStatus) received.getObject();
			if (status == null) {
				System.out.println("received message: " + "null returned");
			} else {
				System.out.println("Successfully got object lets send it to the collision client");
				CollisionInfo latest = (CollisionInfo) manager.getCollisionInfo(status);
				
				/* Reply to the clients temporary queue via the getjmsreplyto field */
				MessageProducer producer = session.createProducer(null);
				producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
				ObjectMessage response = session.createObjectMessage((Serializable) latest);
				response.setJMSCorrelationID(received.getJMSCorrelationID());
				producer.send(received.getJMSReplyTo(), response);
			}

		} catch (JMSException e) {
		}
	}
}
